package cn.tedu.fy.pethome.service.impl;

import cn.tedu.fy.pethome.ex.ServiceException;
import cn.tedu.fy.pethome.mapper.UserChangePasswordLogMapper;
import cn.tedu.fy.pethome.mapper.UserMapper;
import cn.tedu.fy.pethome.pojo.domain.CsmallAuthenticationInfo;
import cn.tedu.fy.pethome.pojo.dto.ChangePasswordDTO;
import cn.tedu.fy.pethome.pojo.dto.UserRegistryDTO;
import cn.tedu.fy.pethome.pojo.entity.User;
import cn.tedu.fy.pethome.pojo.entity.UserChangePasswordLog;
import cn.tedu.fy.pethome.pojo.vo.UserRegisterVO;
import cn.tedu.fy.pethome.pojo.vo.UserVO;
import cn.tedu.fy.pethome.service.IUserServiceImpl;
import cn.tedu.fy.pethome.web.JsonResult;
import cn.tedu.fy.pethome.web.ServiceCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestBody;

import javax.validation.Valid;
import java.rmi.ServerException;
import java.time.LocalDateTime;

@Service
@Slf4j
public class UserServiceImpl implements IUserServiceImpl {

    @Autowired
    private UserMapper userMapper;
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private UserChangePasswordLogMapper userChangePasswordLogMapper;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    /**查询用户信息*/
    @Override
    public UserVO queryOneUser(String username) {
        return userMapper.selectUserByUsername(username);
    }
    //用户注册
    @Override
    public void doRegister(@RequestBody  @Valid UserRegistryDTO userRegistyDTO) {
        //TODO 验证

        //用户注册DTO信息转换为用户基本信息user类
        User user=new User();
        BeanUtils.copyProperties(userRegistyDTO,user);
        //用户密码加密
        user.setPassword(passwordEncoder.encode(userRegistyDTO.getPassword()));
        //插入数据库
        userMapper.insertUser(user);


    }

    @Override
    public void checkValue(String value, String type) {
        //检查注册信息是否与数据库重复
        int count= userMapper.selectExistByUsernameOrPhoneOrEmail(value,type);
        if (count>0){
            if (type.equals("username")){
                throw  new ServiceException(ServiceCode.ERR_CONFLICT,"注册用户名已经存在");
            }
            if(type.equals("phone")) {
                throw new ServiceException(ServiceCode.ERR_CONFLICT, "注册手机号已存在");
            }
            if(type.equals("email")) {
                throw new ServiceException(ServiceCode.ERR_CONFLICT, "注册邮箱已存在");
            }
        }


    }

    //验证密码
    @Override
    public void renewPassword(@RequestBody @Valid ChangePasswordDTO changePasswordDTO, String token) {
        //TODO 验证

        //获取userId
        Long userId=getUserId();
        //查询用户信息
        User user=userMapper.selectUserById(userId);
        log.debug("查询到用户信息:{}",user);
        //验证密码
        boolean matches= passwordEncoder.matches(changePasswordDTO.getPassword(),user.getPassword());
        log.debug("用户密码:{},输入密码:{}",user.getPassword(),changePasswordDTO.getPassword());
        if (!matches){
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND,"密码错误请重新输入");
        }
        //加密密码
        String encodedNewPassword = passwordEncoder.encode(changePasswordDTO.getPassword());
        log.debug("加密后密码:{}",encodedNewPassword);
        userMapper.updatePasswordById(userId,encodedNewPassword);

        //记录用户修改密码的日志
        UserChangePasswordLog userChangePasswordLog=new UserChangePasswordLog();
        //获取当前系统时间
        LocalDateTime now=LocalDateTime.now();
        userChangePasswordLog.setGmtChangePassword(now);
        userChangePasswordLog.setGmtCreate(now);
        userChangePasswordLog.setGmtModified(now);
        userChangePasswordLog.setIp(changePasswordDTO.getIp());
        userChangePasswordLog.setUserAgent(changePasswordDTO.getUserAgent());
        userChangePasswordLog.setNewPassword(encodedNewPassword);
        userChangePasswordLog.setUserId(userId);
        userChangePasswordLog.setUsername(user.getUsername());
        userChangePasswordLog.setNickname(user.getNickname());
        log.debug("修改密码日志信息:{}",userChangePasswordLog);
        userChangePasswordLogMapper.insertChangePasswordLog(userChangePasswordLog);

        //清空当前的认证数据,将token放入黑名单,修改密码后重新登录
        String lockedTokenList="token_list_.lock";
        Long add=stringRedisTemplate.boundSetOps(lockedTokenList).add(token);
        log.debug("清空认证信息{}",add);

    }



    private Long getUserId() {
        CsmallAuthenticationInfo userInfo=getUserInfo();
        return userInfo.getId();
    }

    private CsmallAuthenticationInfo getUserInfo() {
        //从security环境获取username,先拿到认证authentication
        log.debug("获取用户jwt认证权限getUserInfo执行了");
        UsernamePasswordAuthenticationToken authentication=(UsernamePasswordAuthenticationToken)
                SecurityContextHolder.getContext().getAuthentication();
        //如果非空则调用UserVO
        if (authentication==null){
            CsmallAuthenticationInfo csmallAuthenticationInfo=(CsmallAuthenticationInfo)
                    authentication.getCredentials();
            log.debug("----------------------{}",csmallAuthenticationInfo);
            return csmallAuthenticationInfo;
        }else {
            throw new ServiceException(ServiceCode.ERR_JWT_INVALID,"未登录");
        }


    }


}
